// File: spsc_ring_buffer.hpp
#pragma once

#include <atomic>
#include <cstddef>
#include <vector>

#include "macros.h"

namespace Common {

  /**
   * @brief 单生产者单消费者（SPSC）环形缓冲无锁队列。
   *
   *  - 模板参数 @tparam T 指定队列元素类型。
   *  - 利用固定容量环形数组，实现写指针与读指针的无锁推进。
   *  - 单生产者与单消费者各自独占写入与读取，因此无需额外同步。
   *
   * ⚠️ 设计约束：
   *  - 仅读写线程各限一条；多线程竞争同一端将破坏内存模型。
   *  - 容量固定；建议预估峰值流量后设定容量。
   */
  template<typename T>
  class SPSCRingBuffer final {
  public:
    using value_type = T;

    explicit SPSCRingBuffer(std::size_t capacity)
        : buffer_(capacity + 1),
          capacity_(capacity + 1) {
      ASSERT(capacity > 0, "Capacity must be positive.");
    }

    /**
     * @brief 入队一个元素（单生产者调用）。
     *
     * @param value 待写入的数据。
     * @return 若队列未满返回 true；否则返回 false。
     * @note 通过“空槽 = capacity - size - 1”区分满/空。
     */
    bool push(const T &value) noexcept {
      const std::size_t tail = tail_.load(std::memory_order_relaxed);
      const std::size_t next_tail = increment(tail);
      if (next_tail == head_.load(std::memory_order_acquire)) {
        return false; // 队列已满
      }
      buffer_[tail] = value;
      tail_.store(next_tail, std::memory_order_release);
      return true;
    }

    /**
     * @brief 出队一个元素（单消费者调用）。
     *
     * @param out_value 若成功出队，写入此引用。
     * @return 队列非空返回 true；否则 false。
     */
    bool pop(T &out_value) noexcept {
      const std::size_t head = head_.load(std::memory_order_relaxed);
      if (head == tail_.load(std::memory_order_acquire)) {
        return false; // 队列为空
      }
      out_value = buffer_[head];
      head_.store(increment(head), std::memory_order_release);
      return true;
    }

    /**
     * @brief 近似返回当前元素数量。
     *
     * @note 由于是无锁结构，该值仅供参考。
     */
    std::size_t size() const noexcept {
      const std::size_t head = head_.load(std::memory_order_acquire);
      const std::size_t tail = tail_.load(std::memory_order_acquire);
      if (tail >= head) {
        return tail - head;
      }
      return capacity_ - (head - tail);
    }

    std::size_t capacity() const noexcept {
      return capacity_ - 1;
    }

  private:
    std::size_t increment(std::size_t index) const noexcept {
      return (index + 1) % capacity_;
    }

    std::vector<T> buffer_;
    const std::size_t capacity_;

    std::atomic<std::size_t> head_{0}; ///< 下一次读取位置（仅消费者写）
    std::atomic<std::size_t> tail_{0}; ///< 下一次写入位置（仅生产者写）
  };

} // namespace Common